<?php

require_once 'vendor/autoload.php';

use Smalot\Cups\Builder\Builder;
use Smalot\Cups\Manager\JobManager;
use Smalot\Cups\Manager\PrinterManager;
use Smalot\Cups\Model\Job;
use Smalot\Cups\Transport\ResponseParser;
use Http\Client\Socket\Client as HttpClient;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

/**
 * IPP简单修复器
 * 使用基本网络功能解决IPP打印问题
 */
class IPPSimpleFix
{
    private string $printerIp;
    private int $printerPort;
    private Builder $builder;
    private ResponseParser $responseParser;

    public function __construct(string $printerIp = '10.1.0.12', int $printerPort = 631)
    {
        $this->printerIp = $printerIp;
        $this->printerPort = $printerPort;
        $this->builder = new Builder();
        $this->responseParser = new ResponseParser();
        
        echo "🔧 IPP简单修复器\n";
        echo "目标打印机: {$this->printerIp}:{$this->printerPort}\n";
        echo str_repeat('=', 60) . "\n\n";
    }

    /**
     * 运行简单修复
     */
    public function runSimpleFix(): bool
    {
        echo "🚀 开始IPP简单修复...\n\n";
        
        // 方法1: 使用cURL修复
        if ($this->tryCurlFix()) {
            echo "✅ cURL修复成功！\n";
            return true;
        }
        
        // 方法2: 使用file_get_contents修复
        if ($this->tryFileGetContentsFix()) {
            echo "✅ file_get_contents修复成功！\n";
            return true;
        }
        
        // 方法3: 使用fsockopen修复
        if ($this->tryFsockopenFix()) {
            echo "✅ fsockopen修复成功！\n";
            return true;
        }
        
        echo "❌ 所有简单修复方法都失败了\n";
        return false;
    }

    /**
     * 方法1: 使用cURL修复
     */
    private function tryCurlFix(): bool
    {
        echo "🌐 尝试cURL修复...\n";
        
        if (!function_exists('curl_init')) {
            echo "   ❌ cURL扩展未安装\n";
            return false;
        }
        
        try {
            $customClient = new class($this->printerIp, $this->printerPort) implements \Http\Client\HttpClient {
                private string $targetIp;
                private int $targetPort;
                
                public function __construct(string $ip, int $port)
                {
                    $this->targetIp = $ip;
                    $this->targetPort = $port;
                }
                
                public function sendRequest(RequestInterface $request): ResponseInterface
                {
                    $ch = curl_init();
                    
                    $url = "http://{$this->targetIp}:{$this->targetPort}" . ($request->getUri()->getPath() ?: '/ipp/print');
                    
                    curl_setopt_array($ch, [
                        CURLOPT_URL => $url,
                        CURLOPT_CUSTOMREQUEST => $request->getMethod(),
                        CURLOPT_POSTFIELDS => (string)$request->getBody(),
                        CURLOPT_RETURNTRANSFER => true,
                        CURLOPT_TIMEOUT => 30,
                        CURLOPT_CONNECTTIMEOUT => 10,
                        CURLOPT_HTTPHEADER => [
                            'Content-Type: application/ipp',
                            'Host: ' . $this->targetIp . ':' . $this->targetPort,
                            'User-Agent: CUPS-IPP-cURL/1.0',
                            'Accept: application/ipp',
                            'Accept-Language: en-us',
                            'Accept-Encoding: identity',
                            'Connection: close'
                        ],
                        CURLOPT_HEADER => false,
                        CURLOPT_NOBODY => false,
                        CURLOPT_FOLLOWLOCATION => false,
                        CURLOPT_SSL_VERIFYPEER => false,
                        CURLOPT_SSL_VERIFYHOST => false,
                        CURLOPT_VERBOSE => false
                    ]);
                    
                    $response = curl_exec($ch);
                    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                    $error = curl_error($ch);
                    curl_close($ch);
                    
                    if ($response === false) {
                        throw new \Exception("cURL错误: {$error}");
                    }
                    
                    return new \GuzzleHttp\Psr7\Response($httpCode, [], $response);
                }
            };
            
            $jobManager = new JobManager($this->builder, $customClient, $this->responseParser);
            $printerManager = new PrinterManager($this->builder, $customClient, $this->responseParser);
            
            return $this->sendTestJob($jobManager, $printerManager);
            
        } catch (Exception $e) {
            echo "   错误: {$e->getMessage()}\n";
            return false;
        }
    }

    /**
     * 方法2: 使用file_get_contents修复
     */
    private function tryFileGetContentsFix(): bool
    {
        echo "📄 尝试file_get_contents修复...\n";
        
        try {
            $customClient = new class($this->printerIp, $this->printerPort) implements \Http\Client\HttpClient {
                private string $targetIp;
                private int $targetPort;
                
                public function __construct(string $ip, int $port)
                {
                    $this->targetIp = $ip;
                    $this->targetPort = $port;
                }
                
                public function sendRequest(RequestInterface $request): ResponseInterface
                {
                    $url = "http://{$this->targetIp}:{$this->targetPort}" . ($request->getUri()->getPath() ?: '/ipp/print');
                    
                    $context = stream_context_create([
                        'http' => [
                            'method' => $request->getMethod(),
                            'header' => [
                                'Content-Type: application/ipp',
                                'Host: ' . $this->targetIp . ':' . $this->targetPort,
                                'User-Agent: CUPS-IPP-FileGetContents/1.0',
                                'Accept: application/ipp',
                                'Accept-Language: en-us',
                                'Accept-Encoding: identity',
                                'Connection: close'
                            ],
                            'content' => (string)$request->getBody(),
                            'timeout' => 30,
                            'ignore_errors' => true
                        ]
                    ]);
                    
                    $response = file_get_contents($url, false, $context);
                    
                    if ($response === false) {
                        throw new \Exception('file_get_contents请求失败');
                    }
                    
                    // 获取HTTP状态码
                    $httpCode = 200;
                    if (isset($http_response_header)) {
                        foreach ($http_response_header as $header) {
                            if (preg_match('/HTTP\/\d\.\d (\d+)/', $header, $matches)) {
                                $httpCode = (int)$matches[1];
                                break;
                            }
                        }
                    }
                    
                    return new \GuzzleHttp\Psr7\Response($httpCode, [], $response);
                }
            };
            
            $jobManager = new JobManager($this->builder, $customClient, $this->responseParser);
            $printerManager = new PrinterManager($this->builder, $customClient, $this->responseParser);
            
            return $this->sendTestJob($jobManager, $printerManager);
            
        } catch (Exception $e) {
            echo "   错误: {$e->getMessage()}\n";
            return false;
        }
    }

    /**
     * 方法3: 使用fsockopen修复
     */
    private function tryFsockopenFix(): bool
    {
        echo "🔌 尝试fsockopen修复...\n";
        
        try {
            $customClient = new class($this->printerIp, $this->printerPort) implements \Http\Client\HttpClient {
                private string $targetIp;
                private int $targetPort;
                
                public function __construct(string $ip, int $port)
                {
                    $this->targetIp = $ip;
                    $this->targetPort = $port;
                }
                
                public function sendRequest(RequestInterface $request): ResponseInterface
                {
                    $fp = fsockopen($this->targetIp, $this->targetPort, $errno, $errstr, 30);
                    if (!$fp) {
                        throw new \Exception("连接失败: {$errstr} ({$errno})");
                    }
                    
                    stream_set_timeout($fp, 30);
                    
                    // 构建HTTP请求
                    $path = $request->getUri()->getPath() ?: '/ipp/print';
                    $body = (string)$request->getBody();
                    
                    $httpRequest = $request->getMethod() . " {$path} HTTP/1.1\r\n";
                    $httpRequest .= "Host: {$this->targetIp}:{$this->targetPort}\r\n";
                    $httpRequest .= "Content-Type: application/ipp\r\n";
                    $httpRequest .= "Content-Length: " . strlen($body) . "\r\n";
                    $httpRequest .= "User-Agent: CUPS-IPP-Fsockopen/1.0\r\n";
                    $httpRequest .= "Accept: application/ipp\r\n";
                    $httpRequest .= "Accept-Language: en-us\r\n";
                    $httpRequest .= "Accept-Encoding: identity\r\n";
                    $httpRequest .= "Connection: close\r\n";
                    $httpRequest .= "\r\n";
                    $httpRequest .= $body;
                    
                    // 发送请求
                    fwrite($fp, $httpRequest);
                    
                    // 读取响应
                    $response = '';
                    while (!feof($fp)) {
                        $response .= fread($fp, 8192);
                    }
                    
                    fclose($fp);
                    
                    // 解析HTTP响应
                    $parts = explode("\r\n\r\n", $response, 2);
                    $headers = $parts[0] ?? '';
                    $body = $parts[1] ?? '';
                    
                    // 提取状态码
                    preg_match('/HTTP\/\d\.\d (\d+)/', $headers, $matches);
                    $statusCode = isset($matches[1]) ? (int)$matches[1] : 200;
                    
                    return new \GuzzleHttp\Psr7\Response($statusCode, [], $body);
                }
            };
            
            $jobManager = new JobManager($this->builder, $customClient, $this->responseParser);
            $printerManager = new PrinterManager($this->builder, $customClient, $this->responseParser);
            
            return $this->sendTestJob($jobManager, $printerManager);
            
        } catch (Exception $e) {
            echo "   错误: {$e->getMessage()}\n";
            return false;
        }
    }

    /**
     * 发送测试打印任务
     */
    private function sendTestJob(JobManager $jobManager, PrinterManager $printerManager): bool
    {
        try {
            $printerUri = "ipp://{$this->printerIp}:{$this->printerPort}/ipp/print";
            
            echo "   🔍 查找打印机: {$printerUri}\n";
            $printer = $printerManager->findByUri($printerUri);
            if (!$printer) {
                echo "   ❌ 无法找到打印机\n";
                return false;
            }
            
            echo "   ✅ 找到打印机: {$printer->getName()}\n";
            
            $job = new Job();
            $job->setName('IPP简单修复测试');
            $job->setUsername('simple_fix');
            $job->setCopies(1);
            $job->setPrinterUri($printerUri);
            $job->addText($this->createTestContent());
            
            echo "   📤 发送测试打印任务...\n";
            $result = $jobManager->send($printer, $job);
            
            if ($result) {
                echo "   ✅ 测试打印任务发送成功\n";
                return true;
            } else {
                echo "   ❌ 测试打印任务发送失败\n";
                return false;
            }
            
        } catch (Exception $e) {
            echo "   ❌ 发送测试任务时出错: {$e->getMessage()}\n";
            return false;
        }
    }

    /**
     * 创建测试内容
     */
    private function createTestContent(): string
    {
        return "IPP简单修复测试\n" .
               "==================\n" .
               "时间: " . date('Y-m-d H:i:s') . "\n" .
               "打印机: {$this->printerIp}:{$this->printerPort}\n" .
               "测试类型: 简单修复\n" .
               "\n" .
               "如果您看到这个文档，说明IPP简单修复成功！\n" .
               "\n" .
               "修复完成时间: " . date('Y-m-d H:i:s') . "\n";
    }

    /**
     * 测试网络连接
     */
    public function testConnection(): array
    {
        $results = [
            'ping' => false,
            'port' => false,
            'http' => false
        ];
        
        echo "🔍 测试网络连接...\n";
        
        // Ping测试
        echo "   Ping测试: ";
        $command = "ping -n 1 -w 1000 {$this->printerIp}";
        $output = [];
        $returnCode = 0;
        exec($command . ' 2>&1', $output, $returnCode);
        $results['ping'] = ($returnCode === 0);
        echo $results['ping'] ? "✅ 成功\n" : "❌ 失败\n";
        
        // 端口测试
        echo "   端口631测试: ";
        $connection = @fsockopen($this->printerIp, $this->printerPort, $errno, $errstr, 5);
        if ($connection) {
            fclose($connection);
            $results['port'] = true;
            echo "✅ 开放\n";
        } else {
            echo "❌ 关闭\n";
        }
        
        // HTTP测试
        echo "   HTTP测试: ";
        $context = stream_context_create([
            'http' => [
                'method' => 'GET',
                'timeout' => 10,
                'header' => 'User-Agent: IPP-Simple-Fix/1.0'
            ]
        ]);
        
        $response = @file_get_contents("http://{$this->printerIp}", false, $context);
        $results['http'] = ($response !== false);
        echo $results['http'] ? "✅ 可访问\n" : "❌ 无法访问\n";
        
        return $results;
    }
}

// 运行简单修复
try {
    // 可以修改IP地址为您的打印机IP
    $simpleFix = new IPPSimpleFix('10.1.0.12', 631);
    
    // 先测试网络连接
    $connectionResults = $simpleFix->testConnection();
    echo "\n";
    
    // 运行修复
    $success = $simpleFix->runSimpleFix();
    
    if ($success) {
        echo "\n🎉 IPP简单修复成功！\n";
        echo "现在可以正常使用IPP打印功能了。\n";
    } else {
        echo "\n😞 IPP简单修复失败。\n";
        echo "建议检查网络连接和打印机设置。\n";
        
        // 提供诊断信息
        echo "\n📊 网络诊断结果:\n";
        echo "   Ping: " . ($connectionResults['ping'] ? "✅" : "❌") . "\n";
        echo "   端口631: " . ($connectionResults['port'] ? "✅" : "❌") . "\n";
        echo "   HTTP: " . ($connectionResults['http'] ? "✅" : "❌") . "\n";
        
        if (!$connectionResults['ping']) {
            echo "\n💡 建议:\n";
            echo "   - 检查打印机IP地址是否正确\n";
            echo "   - 确认打印机已开机并连接网络\n";
        }
        
        if (!$connectionResults['port']) {
            echo "\n💡 建议:\n";
            echo "   - 检查防火墙设置\n";
            echo "   - 确认打印机IPP服务已启用\n";
        }
    }
    
    exit($success ? 0 : 1);
    
} catch (Exception $e) {
    echo "❌ 简单修复器运行失败: {$e->getMessage()}\n";
    echo "📍 位置: {$e->getFile()}:{$e->getLine()}\n";
    exit(1);
}